package com.lizi.apidoc.builder;

import com.lizi.apidoc.constants.DocGlobal;
import com.lizi.apidoc.model.ApiConfig;
import com.lizi.apidoc.model.ApiObjectProperty;
import com.lizi.apidoc.model.SourceCodePath;
import com.lizi.apidoc.utils.ArraysUtil;
import com.lizi.apidoc.utils.DocUtil;
import com.lizi.apidoc.utils.StringUtil;
import com.thoughtworks.qdox.JavaProjectBuilder;
import com.thoughtworks.qdox.model.JavaClass;
import org.apache.log4j.Logger;

import java.io.File;
import java.nio.charset.Charset;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 类的装载器
 * @author kingman zhangjw@3vjia.com
 * @since 2020-05-07 11:36
 */
public class ClassLoader {

    private Logger logger = Logger.getLogger(ClassLoader.class);

    //region 单例
    private static ClassLoader ourInstance = new ClassLoader();
    public static ClassLoader getInstance() {
        return ourInstance;
    }
    private ClassLoader(){ }
    //endregion

    //region 私有变量
    private JavaProjectBuilder javaProjectBuilder;
    private ApiConfig apiConfig;

//    private Collection<JavaClass> allJavaClasses = new ArrayList<>();
    private Map<String, JavaClass> classFilesMap = new ConcurrentHashMap<>(); //源码路径下所有的类。
    private Collection<JavaClass> filterPackageJavaClasses = new ArrayList<>();//经过packageFilter过滤后的类文件,一般是controller
    private Map<String, List<ApiObjectProperty>> propertyMap = new ConcurrentHashMap<>(); //类中的属性
    //endregion

    //region 初始化
    public void init(ApiConfig apiConfig){
        if (null == apiConfig) {
            throw new NullPointerException("ApiConfig can't be null.");
        }
        this.apiConfig = apiConfig;
        javaProjectBuilder = new JavaProjectBuilder();

        if (StringUtil.isNullOrEmpty(apiConfig.getServerUrl())) {
            apiConfig.setServerUrl(DocGlobal.DEFAULT_SERVER_URL);
        }
        javaProjectBuilder.setEncoding(Charset.defaultCharset().toString());

        this.loadJavaSource(apiConfig.getSourceCodePaths());
        this.initClassFilesMap();
    }
    /**
     * 加载源代码目录
     * @param paths
     */
    private void loadJavaSource(List<SourceCodePath> paths) {
        if (ArraysUtil.isNullOrEmpty(paths)) {
            javaProjectBuilder.addSourceTree(new File(DocGlobal.PROJECT_CODE_PATH));
        } else {
            for (SourceCodePath path : paths) {
                if (null == path) {
                    continue;
                }
                String strPath = path.getPath();
                if (!StringUtil.isNullOrEmpty(strPath)) {
                    strPath = strPath.replace("\\", "/");
                    javaProjectBuilder.addSourceTree(new File(strPath));
                }
            }
        }
    }

    /**
     * 加载类文件
     */
    private void initClassFilesMap() {
//        allJavaClasses = javaProjectBuilder.getClasses();
        for (JavaClass cls : javaProjectBuilder.getClasses()) {
            String classFullName = cls.getFullyQualifiedName();
            classFilesMap.put(classFullName, cls); //全路径类，key存在时，不覆盖

            //region 过滤包名的类
            if(!ArraysUtil.isNullOrEmpty(apiConfig.getPackageFilters())){
                for(String filter : apiConfig.getPackageFilters())
                {
                    if (DocUtil.isMatch(filter, cls.getCanonicalName())) {
                        filterPackageJavaClasses.add(cls);
                    }
                }
            }
            //endregion

            //region 加载类中的字段
            if (!propertyMap.containsKey(classFullName)) {
                List<ApiObjectProperty> apiObjectProperties = ClassPropertyGetter.getProperties(cls);
                if(!ArraysUtil.isNullOrEmpty(apiObjectProperties)){
                    propertyMap.put(classFullName,apiObjectProperties);
                }
            }
            //endregion

        }
    }
    //endregion

    //region 公开方法
    /**
     * 得到过滤包后的java类信息,一般controller类
     * @return
     */
    public Collection<JavaClass> getFilterPackageJavaClasses() {
        if (filterPackageJavaClasses == null) {
            filterPackageJavaClasses = new ArrayList<>();
        }
        return filterPackageJavaClasses;
    }

    /**
     * 得到java的类信息
     * @param fullTypeName
     * @return
     */
    public JavaClass getJavaClassByFullTypeName(String fullTypeName){
        if(classFilesMap.containsKey(fullTypeName)){
            return classFilesMap.get(fullTypeName);
        }
        return null;
    }

    /**
     * 得到某个类的字段信息
     * @param classFullTypeName
     * @return
     */
    public List<ApiObjectProperty> getObjectPropertyByFullTypeName(String classFullTypeName)
    {
        if(propertyMap.containsKey(classFullTypeName)){
            return propertyMap.get(classFullTypeName);
        }
        return null;
    }
    //endregion

}
